package com.ge.rpc.proxy;

import com.ge.rpc.RpcApplication;
import com.ge.rpc.config.RpcConfig;
import com.ge.rpc.constant.RpcConstant;
import com.ge.rpc.fault.retry.RetryStrategy;
import com.ge.rpc.fault.retry.RetryStrategyFactory;
import com.ge.rpc.fault.tolerant.TolerantStrategy;
import com.ge.rpc.fault.tolerant.TolerantStrategyFactory;
import com.ge.rpc.loadbalancer.LoadBalancer;
import com.ge.rpc.loadbalancer.LoadBalancerFactory;
import com.ge.rpc.model.RpcRequest;
import com.ge.rpc.model.RpcResponse;
import com.ge.rpc.model.ServiceMetaInfo;
import com.ge.rpc.registry.Registry;
import com.ge.rpc.registry.RegistryFactory;
import com.ge.rpc.serializer.Serializer;
import com.ge.rpc.serializer.SerializerFactory;
import com.ge.rpc.server.tcp.VertxTcpClient;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;

/**
 * 服务代理（JDK动态代理）
 * JDK动态代理相对简单易用，但只能对接口进行代理；基于字节码生成的动态代理（如CGLIB）可以对任何类进行代理，但性能略低
 */
public class ServiceProxy implements InvocationHandler {

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Exception {
        // 指定序列化器
        final Serializer serializer = SerializerFactory.getInstance(RpcApplication.getRpcConfig().getSerializer());

        // 发送请求
        String serviceName = method.getDeclaringClass().getName();
        RpcRequest rpcRequest = RpcRequest.builder()
                .serviceName(serviceName)
                .methodName(method.getName())
                .parameterTypes(method.getParameterTypes())
                .args(args)
                .build();

        RpcConfig rpcConfig = RpcApplication.getRpcConfig();
        Registry registry = RegistryFactory.getInstance(rpcConfig.getRegistryConfig().getRegistry());
        ServiceMetaInfo serviceMetaInfo = new ServiceMetaInfo();
        serviceMetaInfo.setServiceName(serviceName);
        serviceMetaInfo.setServiceVersion(RpcConstant.DEFAULT_SERVICE_VERSION);
        List<ServiceMetaInfo> serviceMetaInfoList = registry.serviceDiscovery(serviceMetaInfo.getServiceKey());
        if (serviceMetaInfoList.isEmpty()) {
            throw new RuntimeException("暂无服务地址");
        }
        // 负载均衡
        LoadBalancer loadBalancer = LoadBalancerFactory.getInstance(rpcConfig.getLoadBalancer());
        Map<String, Object> requestParams = new HashMap<>();
        // 将调用方法名（请求路径）作为负载均衡参数
        requestParams.put("methodName", rpcRequest.getMethodName());
        ServiceMetaInfo metaInfo = loadBalancer.select(requestParams, serviceMetaInfoList);
        RpcResponse rpcResponse;
        // 补充容错机制
        try {
            // 使用重试机制
            RetryStrategy retryStrategy = RetryStrategyFactory.getInstance(rpcConfig.getRetryStrategy());
            // 发送 TCP 请求
            rpcResponse = retryStrategy.doRetry(() ->
                VertxTcpClient.doRequest(rpcRequest, metaInfo)
            );
        } catch (Exception e) {
            TolerantStrategy tolerantStrategy = TolerantStrategyFactory.getInstance(rpcConfig.getTolerantStrategy());
            rpcResponse = tolerantStrategy.doTolerant(null, e);
        }
        return rpcResponse.getData();
    }
}
